home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Gold Collection
/
Software Vault - The Gold Collection (American Databankers) (1993).ISO
/
cdr47
/
mfkasm.zip
/
386_DOS.MAC
< prev
next >
Wrap
Text File
|
1993-06-01
|
24KB
|
828 lines
;------------------------------------------------------
;386_dos.mac Begun:Mon 05-04-1992 Revised:Tue 07-28-1992
;M. F. Kaplon
;Macros using the DOSxxxx calls of OS/2 2.0
;Since using the Library that uses C-calling convention must push
;parameters in reverse order and reset the stack pointer.
;All Macro Names begin with $ and are followed in all
;cases of a DOS.... call with the name of the call
;Each DOS call macro resets the stack pointer based on number of pushes
;and the type of the push ( DWORDs)
;------------------------------------------------------
EXTRN DosAllocMem:near,DosBeep:near,DosCreateThread:near,DosDevIOCtl:near
EXTRN DosExecPgm:near,DosExit:near,DosFreeMem:near,DosFreeModule:near
EXTRN DosGetInfoBlocks:near,DosKillThread:near
EXTRN DosLoadModule:near,DosOpen:near,DosPutMessage:near
EXTRN DosQueryModuleHandle:near,DosQueryModuleName:near,DosQueryProcAddr:near
EXTRN DosQueryProcType:near,DosRead:near,DosSleep:near,DosWrite:near
;-------------------------- STRUCTURES --------------------------
KbdDataIn STRUCT ;structure for KbdCharIn and KbdPeek
Char BYTE ?
Scan BYTE ?
Status BYTE ? ;Bits defined p 574 Duncan
Rsvd BYTE 0
Shift WORD ? ;Keyboard Shift State Bits defined p 574 Duncan
Time DWORD ? ;msec since system turned on/restarted
KbdDataIn ENDS ;Usable ONLY in OS/2 FullScreen Window
DateTime STRUCT ;structure for DateTime Info
Hour BYTE ? ;0-23
Minute BYTE ? ;0-59
Second BYTE ? ;0-59
Hundrs BYTE ? ;0-99 hundredths of a second
Day BYTE ? ;1-31
Month BYTE ? ;1-12
Year WORD ? ;1980-2079
TimeZone WORD ? ;TimeZone(minutes± GMT, 300 = US EST,-1=undefined)
DateTime ENDS
;------------------------- General Purpose Macros --------------------------
$Alarm MACRO ;Makes a nice up and down sound
$DosBeep 300,300
$DosBeep 600,300
$DosBeep 300,300
ENDM
$BufLength MACRO BufAdr ;returns length of ASCII0 String at BufAdr in AX
push esi
push ebx
xor ebx,ebx
mov esi,BufAdr
.WHILE byte ptr [esi+ebx] != 0
inc ebx
; .IF ebx > 64
; $DosWriteMsg <nl,"exceeded 64 bytes long",nl>
; $DosExit
; .ENDIF
.ENDW
mov eax,ebx
pop ebx
pop esi
ENDM
$CLS MACRO ;clear screen with DosWrite
local c0
mov cx,24
c0:
$DosWriteMsg nl
loop c0
ENDM
; Concantenate String S2 to end of String S1 and place at S3
; S3 buffer must be long enough to hold S1+S2. S3 is 0 terminates
; copy S1 to buffer S3 and then add S2 at end
$ConcantS1andS2toS3 MACRO S1,S2,S3
pusha
mov edi,offset S3
mov esi,offset S1
mov ecx,LENGTHOF S1
rep movsb
mov esi,offset S2
mov ecx,LENGTHOF S2
rep movsb
inc edi
mov byte ptr [edi],0 ;NULL Terminate
popa
ENDM
$DefineDosBufs MACRO ;Define Buffers used by Dosroutines
nwritten DWORD ? ;for those programs requiring # written storage
ReadBuf BYTE 5 dup(?)
ENDM
$DefineNumBufs MACRO ;Define Buffers used for Storage for Num conversion
B_Buf BYTE 3 dup(?)
W_Buf BYTE 5 dup(?)
DW_Buf BYTE 10 dup(0)
Bit8Str BYTE 8 dup(?)
Bit16Str BYTE 16 dup(?)
Bit32Str BYTE 32 dup(?)
ten DWORD 10 ;used for AsciiToWord
lth DWORD ? ;used for AsciiToWord
errId DWORD ?
ENDM
; Display at current row + 1 Err_Num " Error Calling DOS Function FuncName"
$DosErrMsg MACRO FuncName ;FuncName passed in calling macros
$DWordToAscii eax,DW_Buf
$NewLine
$NewLine
$DosWriteMsgAT DW_Buf
$DosWriteMsg " Error calling Dos CP Function "
$DosWriteMsg FuncName
$DosBeep 500,500
ENDM
$GetCmdLine MACRO ;on return esi has offset of Command Line
.DATA
IFNDEF ppTIB
ppTIB DWORD ? ;To Hold Address of Thread InfoBlock
ppPIB DWORD ? ;To Hold Address of Process InfoBlock
ENDIF
.CODE
push offset ppPIB
push offset ppTIB
call DosGetInfoBlocks
add esp,8 ;update ESP
mov ebx,[ppPIB] ;ebx = address of the PIB
mov esi,[ebx+12] ;esi is offset of command line
ENDM
$KbdData MACRO
.DATA
IFNDEF KbdData
KbdData KbdDataIn {,,,,}
KbdParm WORD 1 ;1 record requested, wait for input
KbdPInOut DWORD 2 ; 2 bytes passed
KbdDInOut DWORD 0 ; 0 bytes passed on input
ENDIF
.CODE
$DosDevIoctl Offset KbdDInOut,10,Offset KbdData,Offset KbdPInOut,2,Offset KbdParm,74h,4,Handle,"Kbd - 74h"
ENDM
$NewLine equ $DosWriteMsg <cr,lf>
$Printf0 MACRO typ,prm ;typ : b/w/s = BYTE/WORD/STRING whose value is val
local msgname,xit ;bb/bw/ = 8bitstring,16bitstring representation of #
pusha ;bx/wx/dwx = Byte/Word/DWord to Hex
IFIDNI <typ>,<x> ;default - nothing entered - exit
jmp xit
ENDIF
IFIDNI <typ>,<b> ;b/w/ followed by b/h is in Binary/Hex representation
xor edx,edx
mov dl,prm
$DWordToAscii edx,DW_Buf
$DosWriteMsgAT DW_Buf
jmp xit
ENDIF
IFIDNI <typ>,<w>
xor edx,edx
mov dx,prm
$DWordToAscii edx,DW_Buf
$DosWriteMsgAT DW_Buf
jmp xit
ENDIF
IFIDNI <typ>,<dw>
$DWordToAscii prm,DW_Buf
$DosWriteMsgAT DW_Buf
jmp xit
ENDIF
IFIDNI <typ>,<bx> ;b/w/ followed by b/h is in Binary/Hex representation
xor edx,edx
mov dl,prm
$DWordToHex edx,DW_Buf
$DosWriteMsgAT DW_Buf
jmp xit
ENDIF
IFIDNI <typ>,<wx>
xor edx,edx
mov dx,prm
$DWordToHex edx,DW_Buf
$DosWriteMsgAT DW_Buf
jmp xit
ENDIF
IFIDNI <typ>,<dwx>
$DWordToHex prm,DW_Buf
$DosWriteMsgAT DW_Buf
jmp xit
ENDIF
IFIDNI <typ>,<bb>
mov al,prm
$ByteToBitString
$DosWriteMsgAT Bit8Str
jmp xit
ENDIF
IFIDNI <typ>, <wb>
mov ax,prm
$WordToBitString
$DosWriteMsgAT Bit16Str
jmp xit
ENDIF
IFIDNI <typ>, <s>
$DosWriteMsg prm
jmp xit
ENDIF
xit:popa
ENDM
$Printf MACRO t1,p1,t2:=<x>,p2,t3:=<x>,p3,t4:=<x>,p4,t5:=<x>,p5,t6:=<x>,p6,t7:=<x>,p7
$Printf0 t1,p1
$Printf0 t2,p2
$Printf0 t3,p3
$Printf0 t4,p4
$Printf0 t5,p5
$Printf0 t6,p6
$Printf0 t7,p7
ENDM
$Wait MACRO ;Beeps and Displays Message "Press <CR> to Continue"
.DATA
IFNDEF OneCharIn
OneCharIn BYTE ?
ENDIF
.CODE
$DosBeep 500,500
$DosWriteMsg <cr,lf,cr,lf," Press <CR> to Continue",cr,lf>
$DosReadKB 2,OneCharIn
ENDM
;------------------------- DOS.... Macros --------------------------
$DosAllocMem MACRO flags,objsize,pbaseaddr
push flags
push objsize
push offset pbaseaddr
call DosAllocMem
add esp,12 ;restore stack pointer
.IF eax != 0
IFDEF NOWIN
$DosErrMsg <" DosAllocMem",nl>
$DosExit
ELSE
$WinErrorMessage msgDosAllocMem
ENDIF
.ENDIF
ENDM
; Sound the bell
$DosBeep MACRO beepf,beepd
pushd beepd ;duration in milliseconds
pushd beepf ;frequency in Hz
call DosBeep
add esp,8 ;restore stack pointer before return
ENDM
$DosCreateThread MACRO arg0,arg1,arg2,arg3,arg4
push arg4 ;StackSize in bytes of Thread
push arg3 ;Thread Flags Bit 0 = 0/1 is start immed/suspended state;Bit 1 = 0/1 is Default methof for stack/precommits all pages in stack
push arg2 ;Argument to be passed to thread - can be pointer
push arg1 ;Address of Code to be executed when thread begins
push arg0 ;Address of DWORD to store ThreadID
call DosCreateThread
add esp,20 ;reset stack
.IF eax != 0
IFDEF NOWIN
$DosErrMsg <" DosCreateThread",nl>
$DosExit
ELSE
$WinErrorMessage msgDosCreateThread
ENDIF
.ENDIF
ENDM
;pdataarea and pparmlist are set up so that if NULL pointer just enter 0, otherwise enter "offset name" when passing
$DosDevIOCtl MACRO arg0,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8
push arg8 ;input/output Pointer
push arg7 ;ULONG input , Length in Bytes of Data Area
push arg6 ;input Address of Data Area
push arg5 ;input/output pointer to Length in Bytes of parms passed/returned
push arg4 ;ULONG input - length in bytes of parm list MaxLnth returned
push arg3 ;input Address of command specific argument list
push arg2 ;ULONG input Device specific function code
push arg1 ;ULONG input Device Category range 0 -255
push arg0 ;HFILE=ULONG input Device Handle value returned by dos Open
call DosDevIOCtl
add esp,36
.IF eax != 0
IFDEF NOWIN
$DosErrMsg <" DosDevIOCtl">
$DosExit
ELSE
$WinErrorMessage msgDosDevIOCtl
ENDIF
.ENDIF
ENDM
$DosExecPgm MACRO ExecMode,Args,ChildExec
.Data
IFNDEF ObjName
ObjName BYTE 100 dup(0) ;receives name of dynlink causing failure
ENDIF
IFNDEF RetCode
RetCode DWORD ?,?
ENDIF
.CODE
push offset ChildExec
push offset RetCode
pushd 0 ;environment pointer 0 is pass parents
push Offset Args ;
pushd ExecMode ;Exec Flags - how executed
pushd LENGTHOF ObjName ;length in bytes of said buffer
push offset ObjName ;buffer to hold name of object casing failure
call DosExecPgm
.IF eax != 0
$DosErrMsg "DosExecPgm"
$DosExit
.ENDIF
add esp,28
ENDM
; Exit Program
$DosExit MACRO
pushd 0 ;value returned
pushd 1 ;terminate process (all threads) (0 = current thread)
call DosExit
ENDM
$DosFreeMem MACRO pbaseaddr
push pbaseaddr
call DosFreeMem
.IF eax != 0
IFDEF NOWIN
$DosErrMsg <" DosFreeMem",nl>
$DosExit
ELSE
$WinErrorMessage msgDosFreeMem
ENDIF
.ENDIF
add esp,4 ;restore stack pointer
ENDM
$DosFreeModule MACRO arg
push arg ;module handle
call DosFreeModule
add esp,4
.IF eax != 0
IFDEF NOWIN
$DosErrMsg <" DosFreeModule",nl>
$DosExit
ELSE
$WinErrorMessage msgDosFreeModule
ENDIF
.ENDIF
ENDM
;TIB and PIB are BLocks, of DWORD items
$DosGetPIB MACRO ;GET Process Information Blocks Info
.DATA
IFNDEF ppPIB
ppPIB DWORD ? ;Address of pointer to PIB
ppTIB DWORD ? ;Address of pointer to TIB
PID DWORD ? ;Process ID
PPID DWORD ? ;Process ID of parent
ModHnd DWORD ? ;Module Handle
CmdLn DWORD ? ;Address of Command Line
Envrn DWORD ? ;Address of Environment
Pstat DWORD ? ;Status of Current Process
Ptype DWORD ? ;Type of Current Process
ENDIF
.CODE
push offset ppPIB
push offset ppTIB
call DosGetInfoBlocks
add esp,8
mov ebx,[ppPIB] ;get PID
mov eax,[ebx]
mov PID,eax
mov eax,[ebx+4] ;get PPID
mov PPID,eax
mov eax,[ebx+8] ;get Module Handle
mov ModHnd,eax
mov eax,[ebx+12] ;get CmdLn
mov CmdLn,eax
mov eax,[ebx+16] ;get environment address
mov Envrn,eax
mov eax,[ebx+20] ;get Status of current Process
mov Pstat,eax
mov eax,[ebx+24] ;get Type of Current Process
mov Ptype,eax
ENDM
$DosKillThread MACRO arg
push arg ;ThreadID
call DosKillThread
add esp,4
.IF eax != 0
IFDEF NOWIN
$DosErrMsg <" DosKillThread",nl>
$DosExit
ELSE
$WinErrorMessage msgDosKillThread
ENDIF
.ENDIF
ENDM
$DosLoadModule MACRO arg0,arg1,arg2,arg3
push arg3 ;offset of module handle variable
push arg2 ;offset of name of dll file
push arg1 ;Buffer Length of DllLoadError
push arg0 ;offset of DllLoadError buffer
call DosLoadModule
add esp,16
.IF eax != 0
IFDEF NOWIN
$DosErrMsg " DosLoadModule Error"
$DosExit
ELSE
; $DWordToAscii eax,DW_Buf
; $ConcantS1andS2ToS3 DW_Buf,msgDosLoadModule,Concanted
$WinErrorMessage msgDosLoadModule
ENDIF
.ENDIF
ENDM
$DosMonOpen MACRO arg1,arg2 ;this is in doscalla.dll
push arg2 ;address of variable to hold handle
push arg1 ;address of device name string ASCZ11
call DosMonOpen
add esp,8
.IF eax != 0
$DosErrMsg <" DosMonoPen Error",nl>
$DosExit
.ENDIF
ENDM
$DosOpen MACRO arg0,arg1,arg2,arg3,arg4,arg5,arg6,arg7
push arg7 ;I/O ULONG Pointer to address Extended Attr Bits 0 if not used
push arg6 ;Input ULONG Open Mode bits
push arg5 ;Input ULONG Oprm Flag bits
push arg4 ;Input ULONG FileAttribute Bits
push arg3 ;Input ULONG Logical file of size
push arg2 ;Output ULONG Address of variable to receive action taken
push arg1 ;Output Address for Handle of file/device
push arg0 ;Input Address of ASCIIZ name of file/device
call DosOpen
add esp,32
.IF eax != 0
IFDEF NOWIN
$DosErrMsg " DosOpen" ;<" DosOpen",nl>
$DosExit
ELSE
$WinErrorMessage msgDosOpen
ENDIF
.ENDIF
ENDM
$DosPutMessage MACRO buffer
local putmsg
.DATA
putmsg BYTE buffer
.CODE
push offset putmsg
push SIZEOF putmsg
push stdout
call DosPutMessage
; .IF eax != 0
; $DosErrMsg "DosPutMessage"
; $DosExit
; .ENDIF
add esp,12
ENDM
$DosQueryModuleHandle MACRO arg1,arg2
push arg2 ;address of DWORD to hold handle returned
push arg1 ;address of ASCIIZ holding full path name of dll
call DosQueryModuleHandle
add esp,8
; .IF eax != 0
; IFDEF NOWIN
; $DosErrMsg <" DosQueryModuleHandle",nl>
; $DosExit
; ELSE
; $WinErrorMessage msgDosQueryModuleHandle
; ENDIF
; .ENDIF
ENDM
$DosQueryProcAddr MACRO arg0,arg1,arg2,arg3
push arg3 ;pointer to DWORD var to hold address
push arg2 ;address of ASCIIZ string holding procedure name
push arg1 ;ordinal # of procedure whose address is desired 0 if name provided
push arg0 ;handle of dynamic link module containing procedure
call DosQueryProcAddr
add esp,16
.IF eax != 0
IFDEF NOWIN
$DosErrMsg " DosQueryProcAddr"
$DosExit
ELSE
$WinErrorMessage msgDosQueryProcAddr
ENDIF
.ENDIF
ENDM
$DosQueryProcType MACRO arg0,arg1,arg2,arg3
push arg3 ;pointer to DWORD var to hold Proc Type
push arg2 ;address of ASCIIZ string holding procedure name
push arg1 ;ordinal # of procedure whose address is desired 0 if name provided
push arg0 ;handle of dynamic link module containing procedure
call DosQueryProcType ;returns 0 if 16 bit, 1 if 32 bit
add esp,16
.IF eax != 0
IFDEF NOWIN
$DosErrMsg " DosQueryProcType"
$DosExit
ELSE
$WinErrorMessage msgDosQueryProcType
ENDIF
.ENDIF
ENDM
$DosRead MACRO bytesread, numreq, address, handle
push offset bytesread
push numreq
push address
push handle
call DosRead
add esp,16 ;restore stack pointer
ENDM
$DosReadKB MACRO numreq,char_in_buf
.DATA
IFNDEF bytesread
bytesread DWORD 0
ENDIF
.CODE
push offset bytesread
pushd numreq
push offset char_in_buf
pushd stdin
call DosRead
add esp,16
ENDM
$DosSleep MACRO delta ;in microseconds
push delta
call DosSleep
add esp,4
ENDM
$DosWrite MACRO lenth ,address,handle
push offset nwritten
push lenth
push address
pushd handle ;unsigned long
call DosWrite
add esp,16 ;restore stack pointer
ENDM
; Write a message to console at current cursor
$DosWriteMsg MACRO messag
local idmessag
.DATA
; IFNDEF messag
idmessag BYTE messag
; ENDIF
.CODE
push offset nwritten
push LENGTHOF idmessag
push offset idmessag
push stdout ;unsigned long
call DosWrite
add esp,16 ;restore stack pointer
ENDM
; Write a message to console at current cursor
;$DosWriteMsg MACRO arg
; local msgname
; .DATA
; IFNDEF messag
; msgname BYTE arg
; ENDIF
; .CODE
; push offset nwritten
; push LENGTHOF msgname
; push offset msgname
; push stdout ;unsigned long
; call DosWrite
; add esp,16 ;restore stack pointer
;ENDM
; Write to console the message stored AT location
; ofset is the offset from start of string "location" to start writing
; devised to get around printing leading spaces in numerical conversions
$DosWriteMsgAT MACRO location ,ofset:=<0> ;0 is default
push offset nwritten
mov eax,LENGTHOF location
sub eax,ofset
push eax
mov eax,offset location
add eax,ofset
push eax
pushd stdout ;unsigned long
call DosWrite
add esp,16 ;restore stack pointer
ENDM
IFDEF NUMBUFS
;-------------------- Binary -> Ascii and Ascii -> Binary --------------------
;Is Passed buffer name - tests to see if all characters in buffer are digits
;If not returns error message and aborts else returns number in eax
;skips over leading and trailing spaces
$GetNumDigits MACRO digbuf
push esi
push edi
mov esi,offset digbuf
mov edi,0
.WHILE 1
.WHILE byte ptr [esi] == 32 ;skip over leading spaces
inc esi
.ENDW
.IF byte ptr [esi] >= 30h
.IF byte ptr [esi] <= 39h
inc edi
inc esi
.ELSE
.BREAK
.ENDIF
.ELSE
.BREAK
.ENDIF
.ENDW ;on exit edi has number of bytes read
.IF edi == 0 ;no valid input
$DosBeep 500,500
$DosWriteMsg <nl,"Invalid Input for ASCIIToDWord - Aborting",nl>
$DosExit
.ENDIF
mov eax,edi
pop edi
pop esi
ENDM
;Convert DWORD to ASCII string at 10 BYTE buffer at digits
;Number to convert moved into EAX, esi points to buffer
$DWordToAscii MACRO num,buf
pusha
mov eax,num
mov esi,offset buf
call DWordToAscii
popa
ENDM
;Convert DWORD to Hex string at 10 BYTE buffer at digits
;Number to convert moved into EAX, esi points to buffer
$DWordToHex MACRO num,buf
pusha
mov eax,num
mov esi,offset buf
call DWordToHex
popa
ENDM
;convert string representing BYTE in BUFF to numeric DWORD
;result returned in EAX)
$AsciiToDWord MACRO Buff
$GetNumDigits Buff ;checks on validity of characters in buffer as well
mov lth,eax
push ebx
push ecx
push edx
push edi
push esi
mov esi,offset Buff
call AsciitoDWord
pop esi
pop edi
pop edx
pop ecx
pop ebx
ENDM
;Convert BYTE to Binary Bit String
;Byte to convert in AL
$ByteToBitString MACRO
pusha
mov edi,offset Bit8Str
call ByteToBitString
popa
ENDM
;Byte to convert in AX
$WordToBitString MACRO
pusha
mov edi,offset Bit16Str
call WordToBitString
popa
ENDM
;----------- Procedures here ---------------
.CODE
;--- Call with esi pointing to buffer to store digit string
DWordToAScii Proc
mov edi,10
xor edx,edx
mov ecx,10
d0: div edi
add edx,30h
push edx ;save on stack
xor edx,edx
loop d0 ;on exit top of stack has first digit, etc.
mov ecx,10
d1: pop edx
mov [esi],dl ;esi has address of buffer
inc esi
loop d1
; now get rid of leading 0's
sub esi,10 ;back to start of string
mov ecx,10
.WHILE byte ptr [esi] == "0"
mov byte ptr [esi]," "
inc esi
dec ecx
.ENDW
.IF cx == 0 ; all spaces
dec esi
mov byte ptr [esi] ,'0'
.ENDIF
ret
DWordToAscii endp
AsciiToDWord proc
mov eax,1
xor edi,edi
xor ebx,ebx
; mov esi,offset Buff
mov ecx,lth
; .WHILE byte ptr [esi] == ' ' ;replace leading spaces with '0'
; mov byte ptr [esi],'0'
; inc esi
; .ENDW
dec lth
add esi,lth ;offset is lnth -1 from 0
w0: push eax
sub byte ptr [esi],30h
mov bl,[esi]
mul bl ;result in EAX
add edi,eax
pop eax
mul ten ;10 x previous value in AX now
dec esi
loopd w0
mov eax,edi
ret
AsciiToDWord endp
;--- Call with esi pointing to buffer to store digit string
DWordToHex Proc
mov edi,16
xor edx,edx
mov ecx,8
d0: div edi
.IF edx <= 9
add edx,30h
.ELSE
add edx,55 ;use caps
.ENDIF
push edx ;save on stack
xor edx,edx
loop d0 ;on exit top of stack has first digit, etc.
mov ecx,8
d1: pop edx
mov [esi],dl ;esi has address of buffer
inc esi
loop d1
mov byte ptr [esi],'H'
; now get rid of leading 0's
;sub esi,10 ;back to start of string
;mov ecx,10
;.WHILE byte ptr [esi] == "0"
; mov byte ptr [esi]," "
; inc esi
; dec ecx
;.ENDW
;.IF cx == 0 ; all spaces
; dec esi
; mov byte ptr [esi] ,'0'
;.ENDIF
ret
DWordToHex endp
WordToBitString proc ;called with edi set to offset of string and # in ax
mov cx,16
dec edi
wb0:inc edi
shl ax,1 ;move most significant bit to carry flag
jc wb1 ;if set copy '1'
mov byte ptr [edi],'0' ;else copy '0'
jmp wb2
wb1:mov byte ptr [edi],'1'
wb2:loop wb0
ret
WordToBitString endp
.CODE
ByteToBitString proc ; al has the number
mov cx,8 ;called with edi set to offset of string
dec edi
bb0:inc edi
shl al,1 ;move most significant bit to carry flag
jc bb1 ;if set copy '1'
mov byte ptr [edi],'0' ;else copy '0'
jmp bb2
bb1:mov byte ptr [edi],'1'
bb2:loop bb0
ret
ByteToBitString endp
ENDIF